﻿#region Using Statemens
using System;
using GameBase.Screens;
using GameBase.Sprites;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StarFox.ScreenComponents;
using StarFox.Sounds;
#endregion

namespace StarFox.Screens
{
    /// <summary>
    /// Xna message screen of the game.
    /// </summary>
    public class DreamBuildPlayScreen : StarFoxScreen
    {
        #region Initialization

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screenManager">The ScreenManager that this Screen is associated to.</param>
        public DreamBuildPlayScreen(ScreenManager screenManager)
            : base(screenManager)
        {
            Name = "DreamBuildPlayScreen";
        }

        /// <summary>
        /// Called when the Screen needs to be initialized.
        /// </summary>
        public override void Initialize()
        {
            Components2D.Add(new DreamBuildPlay(this));

            base.Initialize();
        }

        #endregion

        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    // unload all per-screen loaded assets
                    Content.Unload();

                    base.Dispose(disposing);
                }

                isDisposed = true;
            }
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when 2D content of the Screen needs to be drawn.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        protected override void Draw2D(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(DisplayBuffer);
            GraphicsDevice.Clear(Color.Transparent);

            base.Draw2D(gameTime);

            GraphicsDevice.SetRenderTarget(null);
        }

        #endregion
    }

    #region DreamBuildPlay Message

    /// <summary>
    /// XNA message.
    /// </summary>
    public class DreamBuildPlay : ScreenComponent2D
    {
        #region Fields

        bool toXNA = false;
        TimeSpan totalXNATime = TimeSpan.FromMilliseconds(2000);

        // sprite sheet
        SpriteSheet spriteSheet;

        // dream
        Rectangle dstRectDream;
        Point initPosDream;
        Point endPosDream;

        // build
        Rectangle dstRectBuild;
        Point initPosBuild;
        Point endPosBuild;

        // play
        Rectangle dstRectPlay;
        Point initPosPlay;
        Point endPosPlay;

        // dream, build, play
        Rectangle dstRectDream_s;
        Rectangle dstRectBuild_s;
        Rectangle dstRectPlay_s;

        // xna game studio
        Rectangle dstRectXna;
        Rectangle dstRectGameStudio;

        #endregion

        #region Screen Transitions

        bool toVisible = false;
        bool toHidden = false;
        float trTime = 0.0f;

        /// <summary>
        /// Makes the ScreenComponent2D transition to visible state.
        /// </summary>
        public override void Show()
        {
            toVisible = true;

            // sound notification
            ScreenSound sound = Game.Services.GetService(typeof(ScreenSound)) as ScreenSound;
            if (sound == null)
                throw new InvalidOperationException("Service of type ScreenSound not found");
            sound.DreamBuildPlay();
        }

        /// <summary>
        /// Makes the ScreenComponent2D transition to hidden state.
        /// </summary>
        public override void Hide()
        {
            toHidden = true;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screen">The Screen that this ScreenComponent2D is associated to.</param>
        public DreamBuildPlay(StarFoxScreen screen)
            : base(screen)
        {
            // asset loading
            spriteSheet = Screen.Content.Load<SpriteSheet>(ContentSettings.GetAsset("INTRO_SPRITES"));

            Rectangle auxRect;

            // dream
            auxRect = spriteSheet.SourceRectangle("INTRO_DREAM_BIG");
            dstRectDream = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosDream = new Point((int)(-dstRectDream.Width), (int)(Screen.Height * 0.25f));
            endPosDream = new Point((int)(Screen.Width * 0.015f), initPosDream.Y);
            dstRectDream.Location = initPosDream;
            int nextPos = endPosDream.X + dstRectDream.Width + (int)(Screen.Width * 0.02f);

            // build
            auxRect = spriteSheet.SourceRectangle("INTRO_BUILD_BIG");
            dstRectBuild = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosBuild = new Point(nextPos, (int)(-dstRectBuild.Height));
            endPosBuild = new Point(initPosBuild.X, (int)(Screen.Height * 0.25f));
            dstRectBuild.Location = initPosBuild;
            nextPos = endPosBuild.X + dstRectBuild.Width + (int)(Screen.Width * 0.02f);

            // play
            auxRect = spriteSheet.SourceRectangle("INTRO_PLAY_BIG");
            dstRectPlay = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosPlay = new Point(Screen.Width, (int)(Screen.Height * 0.25f));
            endPosPlay = new Point(nextPos, initPosPlay.Y);
            dstRectPlay.Location = initPosPlay;

            // dream, build, play
            auxRect = spriteSheet.SourceRectangle("INTRO_DREAM_SMALL");
            dstRectDream_s = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectDream_s.Location = new Point((int)(Screen.Width * 0.015f), (int)(Screen.Height * 0.55f));
            nextPos = dstRectDream_s.X + dstRectDream_s.Width + (int)(Screen.Width * 0.020f);

            auxRect = spriteSheet.SourceRectangle("INTRO_BUILD_SMALL");
            dstRectBuild_s = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectBuild_s.Location = new Point(nextPos, (int)(Screen.Height * 0.55f));
            nextPos = dstRectBuild_s.X + dstRectBuild_s.Width + (int)(Screen.Width * 0.020f);

            auxRect = spriteSheet.SourceRectangle("INTRO_PLAY_SMALL");
            dstRectPlay_s = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectPlay_s.Location = new Point(nextPos, (int)(Screen.Height * 0.55f));
            
            // xna game studio
            auxRect = spriteSheet.SourceRectangle("INTRO_XNA");
            dstRectXna = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectXna.Location = new Point((int)(Screen.Width * 0.45f), (int)(Screen.Height * 0.90f));
            nextPos = dstRectXna.X + dstRectXna.Width + (int)(Screen.Width * 0.015f);

            auxRect = spriteSheet.SourceRectangle("INTRO_GAMESTUDIO");
            dstRectGameStudio = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectGameStudio.Location = new Point(nextPos, (int)(Screen.Height * 0.90f));
        }

        #endregion

        #region Update

        /// <summary>
        /// Called when the ScreenComponent2D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            #region Screen Transition

            if (toVisible)
            {
                // update item positions
                float auxTrTime = 1.0f - (float)Math.Pow(1.0f - trTime, 2);
                dstRectDream.X = initPosDream.X + (int)(Math.Abs(initPosDream.X - endPosDream.X) * auxTrTime);
                dstRectBuild.Y = initPosBuild.Y + (int)(Math.Abs(initPosBuild.Y - endPosBuild.Y) * auxTrTime);
                dstRectPlay.X = initPosPlay.X - (int)(Math.Abs(initPosPlay.X - endPosPlay.X) * auxTrTime);

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toVisible = false; toXNA = true; trTime = 0.0f; }
            }
            else if (toHidden)
            {
                // update item positions
                float auxTrTime = 1.0f - (float)Math.Pow(1.0f - trTime, 2);
                dstRectDream.X = endPosDream.X - (int)(Math.Abs(initPosDream.X - endPosDream.X) * auxTrTime);
                dstRectBuild.Y = endPosBuild.Y - (int)(Math.Abs(initPosBuild.Y - endPosBuild.Y) * auxTrTime);
                dstRectPlay.X = endPosPlay.X + (int)(Math.Abs(initPosPlay.X - endPosPlay.X) * auxTrTime);

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toHidden = false; trTime = 0.0f; }
            }

            #endregion

            #region DVW

            if (toXNA)
            {
                // update XNA timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / totalXNATime.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toXNA = false; trTime = 0.0f; Screen.ScreenManager.Clear(new PresentationScreen(Screen.ScreenManager)); }
            }

            #endregion
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when the ScreenComponent2D needs to be drawn.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Draw(GameTime gameTime)
        {
            // dream
            SpriteBatch.Draw(spriteSheet.Texture, dstRectDream, spriteSheet.SourceRectangle("INTRO_DREAM_BIG"), Color.Yellow);

            // build
            SpriteBatch.Draw(spriteSheet.Texture, dstRectBuild, spriteSheet.SourceRectangle("INTRO_BUILD_BIG"), Color.Red);

            // play
            SpriteBatch.Draw(spriteSheet.Texture, dstRectPlay, spriteSheet.SourceRectangle("INTRO_PLAY_BIG"), Color.Yellow);

            // dream, build,  play
            SpriteBatch.Draw(spriteSheet.Texture, dstRectDream_s, spriteSheet.SourceRectangle("INTRO_DREAM_SMALL"), Color.Yellow);
            SpriteBatch.Draw(spriteSheet.Texture, dstRectBuild_s, spriteSheet.SourceRectangle("INTRO_BUILD_SMALL"), Color.Red);
            SpriteBatch.Draw(spriteSheet.Texture, dstRectPlay_s, spriteSheet.SourceRectangle("INTRO_PLAY_SMALL"), Color.Yellow);

            // xna game studio
            SpriteBatch.Draw(spriteSheet.Texture, dstRectXna, spriteSheet.SourceRectangle("INTRO_XNA"), Color.Red);
            SpriteBatch.Draw(spriteSheet.Texture, dstRectGameStudio, spriteSheet.SourceRectangle("INTRO_GAMESTUDIO"), Color.Yellow);
        }

        #endregion
    }

    #endregion
}
